package com.ruoyi.system.util;

import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.Dimension;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

/**
 * @author lixbin
 * @ClassName WebDriverUtil
 * @datetime 2023年 08月 11日 21:13
 * @version: 1.0
 */
@Slf4j
@Component
public class WebDriverUtil {
    private static String chromeDriverPath;
    private static String chromeBinary;

    @Value("${chrome_binary}")
    public void setChromeBinary(String chromeBinary) {
        WebDriverUtil.chromeBinary = chromeBinary;
    }

    @Value("${chrome_driver_path}")
    public void setChromeDriverPath(String chromeDriverPath) {
        WebDriverUtil.chromeDriverPath = chromeDriverPath;
    }

    public static File screenshotForFile(String url, String endId) throws Exception {
        ChromeDriver driver = getChromeDriver();
        if (driver == null) {
            log.error("getChromeDriver error");
            throw new ServiceException("导出失败，请重试");
        }

        try {
            //设置超时，避免有些内容加载过慢导致截不到图
            driver.manage().timeouts().pageLoadTimeout(Duration.ofMinutes(1));
            driver.manage().timeouts().implicitlyWait(Duration.ofMinutes(1));
            driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(1));

            driver.get(url);

            if (StringUtils.isEmpty(endId)) {
                //无加载完成标志，等待1秒
                Thread.sleep(1000);
            } else {
                //加载完成标志
                //等待页面加载完毕，做多等待5秒
                new WebDriverWait(driver, Duration.ofSeconds(5))
                    .until((ExpectedCondition<WebElement>) webDriver -> driver.findElement(By.id(endId)));
            }
            Long height = (Long) driver.executeScript("return document.documentElement.scrollHeight");
            //模拟滑动
            long clientHeight = (Long) driver.executeScript("return document.body.clientHeight");
            long tempHeight = 0;
            while (true) {
                driver.executeScript("window.scrollBy(0,500)");
                tempHeight += 500;
                if (tempHeight >= height) {
                    break;
                }
                Thread.sleep(500);
            }
            //隐藏滚动条
            driver.executeScript("return document.body.style.overflow = 'hidden';");
            //获取高度和宽度一定要在设置URL之后，不然会导致获取不到页面真实的宽高；
            Long width = (Long) driver.executeScript("return document.documentElement.scrollWidth");
            height = (Long) driver.executeScript("return document.documentElement.scrollHeight");

            //设置页面大小
            driver.manage().window().setSize(new Dimension(width.intValue(), height.intValue() + (int) clientHeight));

            File srcFile = driver.getScreenshotAs(OutputType.FILE);
//        FileInputStream inputFile = new FileInputStream(srcFile);
//        byte[] buffer = new byte[(int) srcFile.length()];
//        inputFile.read(buffer);
//        String content = new BASE64Encoder().encode(buffer);
//        System.out.println(content);


//        //设置截图文件保存的路径
//        String screenshotPath = "d:/a2.png";
//        FileUtils.copyFile(srcFile, new File(screenshotPath));

            return srcFile;
        } catch (Exception e) {
            log.error("screenshotForFile for {} error:{}", url, e.getMessage(), e);
            throw new ServiceException("导出失败，请重试!");
        } finally {
            closeChromeDriver(driver);
        }
    }

    public static byte[] screenshotForBytes(String url, String endId) throws Exception {
        ChromeDriver driver = getChromeDriver();
        if (driver == null) {
            log.error("getChromeDriver error");
            throw new ServiceException("导出失败，请重试");
        }

        try {
            //设置超时，避免有些内容加载过慢导致截不到图
            driver.manage().timeouts().pageLoadTimeout(Duration.ofMinutes(1));
            driver.manage().timeouts().implicitlyWait(Duration.ofMinutes(1));
            driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(1));

            driver.get(url);

            if (StringUtils.isEmpty(endId)) {
                //无加载完成标志，等待1秒
                Thread.sleep(1000);
            } else {
                //加载完成标志
                //等待页面加载完毕，做多等待5秒
                new WebDriverWait(driver, Duration.ofSeconds(5))
                    .until((ExpectedCondition<WebElement>) webDriver -> driver.findElement(By.id(endId)));
            }
            Long height = (Long) driver.executeScript("return document.documentElement.scrollHeight");
            //模拟滑动
            long clientHeight = (Long) driver.executeScript("return document.body.clientHeight");
            long tempHeight = 0;
            while (true) {
                driver.executeScript("window.scrollBy(0,500)");
                tempHeight += 500;
                if (tempHeight >= height) {
                    break;
                }
                Thread.sleep(500);
            }
            //隐藏滚动条
            driver.executeScript("return document.body.style.overflow = 'hidden';");
            //获取高度和宽度一定要在设置URL之后，不然会导致获取不到页面真实的宽高；
            Long width = (Long) driver.executeScript("return document.documentElement.scrollWidth");
            height = (Long) driver.executeScript("return document.documentElement.scrollHeight");

            //设置页面大小
            driver.manage().window().setSize(new Dimension(width.intValue(), height.intValue() + (int) clientHeight));

            byte[] srcFile = driver.getScreenshotAs(OutputType.BYTES);
//        FileInputStream inputFile = new FileInputStream(srcFile);
//        byte[] buffer = new byte[(int) srcFile.length()];
//        inputFile.read(buffer);
//        String content = new BASE64Encoder().encode(buffer);
//        System.out.println(content);


//        //设置截图文件保存的路径
//        String screenshotPath = "d:/a2.png";
//        FileUtils.copyFile(srcFile, new File(screenshotPath));

            return srcFile;
        } catch (Exception e) {
            log.error("screenshotForFile for {} error:{}", url, e.getMessage(), e);
            throw new ServiceException("导出失败，请重试!");
        } finally {
            closeChromeDriver(driver);
        }
    }

    public static ChromeDriver getChromeDriver() {
        ChromeOptions options = new ChromeOptions();
        //截屏支持
        options.setCapability("takesScreenshot", true);
        //防止403
        options.addArguments("--remote-allow-origins=*");
        //设置浏览器参数
        options.addArguments("--headless");
        options.addArguments("--no-sandbox");
        options.addArguments("--disable-gpu");
        options.addArguments("--disable-dev-shm-usage");
        options.setHeadless(true);
//        options.addArguments("--disable-infobars", "--start-maximized", "--disable-blink-features=AutomationControlled");
        //屏蔽正受到自动化测试控制的提示
        List<String> list = new ArrayList<>();
        list.add("enable-automation");
        options.setExperimentalOption("excludeSwitches", list);
        options.setBinary(chromeBinary);

        ChromeDriverService service = new ChromeDriverService.Builder()
            .usingDriverExecutable(new File(chromeDriverPath))
            .build();
        ChromeDriver driver = new ChromeDriver(service, options);
        //设置超时，避免有些内容加载过慢导致截不到图
        driver.manage().timeouts().pageLoadTimeout(Duration.ofMinutes(1));
        driver.manage().timeouts().implicitlyWait(Duration.ofMinutes(1));
        driver.manage().timeouts().scriptTimeout(Duration.ofMinutes(1));

        return driver;
    }

    public static void closeChromeDriver(ChromeDriver driver) {
        try {
            driver.close();
            driver.quit();
            log.info("ChromeDriver close success");
        } catch (Exception e) {
            log.error("ChromeDriver close failed: {}", e.getMessage(), e);
        }
    }
}
